using System;
using Microsoft.Research.Kinect.Nui;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Coding4Fun.Kinect.Wpf;

#if NOKINECT
using Microsoft.Xna.Framework.Input;
#endif

namespace KineBall
{
    public struct Option
    {
        public String Name;
        public Vector2 Position;

        public Option(String name, Vector2 position)
        {
            Name = name;
            Position = position;
        }
    }

    enum Options { OnePlayer, TwoPlayers, NUMBER_OF_OPTIONS };

    public class MenuComponent : Microsoft.Xna.Framework.DrawableGameComponent
    {
        #region Fields

#if !NOKINECT
        TrackedSkeleton _kinect;
#endif

        Option[] gameMode; 

        Options currentOption = Options.OnePlayer;

        Vector2 optionTextPosition;

        SpriteBatch spriteBatch;
        SpriteFont menuFont;

        Texture2D backgroundTexture;

        Texture2D titleTexture;

        int titleY = 20;

        Texture2D greenStripeTexture;
        Texture2D rightArrowTexture;
        Texture2D leftArrowTexture;

        Texture2D startButtonTexture;
        Texture2D startButtonSelectedTexture;

        Texture2D exitButtonTexture;
        Texture2D exitButtonSelectedTexture;

        Rectangle startButtonRectangle;
        Rectangle exitButtonRectangle;

        Texture2D handTexture;

        CircularProgressBar circularProgressBar;
        
        Vector currentRightHandPosition;
        Vector oldRightHandPosition;

        int scrollAreaY = 280;
        int scrollAreaHeight = 200;

        Rectangle scrollArea;

        int handleWidth = 200;

        Rectangle rightHandle;
        Rectangle leftHandle;

        int scrollCounter       = 0;
        bool rightScrolling     = false;
        bool leftScrolling      = false;

        int countDown           = 100;

        bool rightTransaction   = false;
        bool leftTransaction    = false;

        public Action onePlayerGame;
        public Action twoPlayerGame;
        public Action gameScore;

        #endregion 


        #region Initialization

        public MenuComponent(Game game)
            : base(game)
        {

        }

        public override void Initialize()
        {
#if NOKINECT
            Vector mousePosition = new Vector();
            mousePosition.X = Mouse.GetState().X;
            mousePosition.Y = Mouse.GetState().Y;

            currentRightHandPosition
                    = oldRightHandPosition
                    = mousePosition;    
#else
            _kinect = Game.Services.GetService(typeof(TrackedSkeleton)) as TrackedSkeleton;

            if (_kinect.trackedSkeleton != null)
            {
                currentRightHandPosition
                    = oldRightHandPosition
                    = _kinect.trackedSkeleton.Joints[JointID.HandRight].ScaleTo(1280, 720, 0.5f, 0.5f).Position;
            }
#endif

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            menuFont = Game.Content.Load<SpriteFont>(@"Fonts/menufont");

            Option onePlayer = new Option(
                "One Player",
                menuFont.MeasureString("One Player") / 2
            );

            Option twoPlayers = new Option(
                "Two Players (unavailable)",
                menuFont.MeasureString("Two Players (unavailable)") / 2
            );

            gameMode = new Option[2];
            gameMode[0] = onePlayer;
            gameMode[1] = twoPlayers;

            backgroundTexture           = Game.Content.Load<Texture2D>(@"Menu/Background");

            titleTexture                = Game.Content.Load<Texture2D>(@"Menu/Title");

            greenStripeTexture          = Game.Content.Load<Texture2D>(@"Menu/Square");
            rightArrowTexture           = Game.Content.Load<Texture2D>(@"Menu/RightArrow");
            leftArrowTexture            = Game.Content.Load<Texture2D>(@"Menu/LeftArrow");

            startButtonTexture          = Game.Content.Load<Texture2D>(@"Menu/StartButton");
            startButtonSelectedTexture  = Game.Content.Load<Texture2D>(@"Menu/StartButtonSelected");

            exitButtonTexture           = Game.Content.Load<Texture2D>(@"Menu/ExitButton");
            exitButtonSelectedTexture   = Game.Content.Load<Texture2D>(@"Menu/ExitButtonSelected");

            startButtonRectangle        = new Rectangle(10, 490, 620, 215);
            exitButtonRectangle         = new Rectangle(650, 490, 620, 215);

            handTexture                 = Game.Content.Load<Texture2D>(@"Menu/Hand");

            circularProgressBar         = new CircularProgressBar(GraphicsDevice, Vector2.Zero, 75.0f, 5.0f, Color.IndianRed);

            optionTextPosition          = new Vector2((GraphicsDevice.Viewport.Width / 2), scrollAreaY + scrollAreaHeight / 2);

            scrollArea                  = new Rectangle(0, scrollAreaY, GraphicsDevice.Viewport.Width, scrollAreaHeight);

            rightHandle                 = new Rectangle(GraphicsDevice.Viewport.Width - handleWidth, scrollAreaY, handleWidth, scrollAreaHeight);
            leftHandle                  = new Rectangle(0, scrollAreaY, handleWidth, scrollAreaHeight);

            base.LoadContent();
        }

        #endregion


        #region Update

        public override void Update(GameTime gameTime)
        {
#if NOKINECT
            Vector mousePosition = new Vector();
            mousePosition.X = Mouse.GetState().X;
            mousePosition.Y = Mouse.GetState().Y;

            oldRightHandPosition = currentRightHandPosition;
            currentRightHandPosition = mousePosition;

            UpdateCursor();
#else
            if (_kinect.trackedSkeleton != null)
            {
                oldRightHandPosition = currentRightHandPosition;
                currentRightHandPosition = _kinect.trackedSkeleton.Joints[JointID.HandRight].ScaleTo(1280, 720, 0.5f, 0.5f).Position;

                UpdateCursor();
            }
#endif
            
            base.Update(gameTime);
        }

        private void UpdateCursor()
        {
            if (InRectangle(rightHandle, currentRightHandPosition))
            {
                rightScrolling = true;
            }
            else if (InRectangle(leftHandle, currentRightHandPosition))
            {
                leftScrolling = true;
            }
            else
            {
                if (InRectangle(startButtonRectangle, currentRightHandPosition))
                {
                    --countDown;
                    circularProgressBar.SetProgress(100 - countDown);
                    circularProgressBar.SetPosition(new Vector2(currentRightHandPosition.X, currentRightHandPosition.Y));

                    if (countDown < 0)
                    {
                        switch (currentOption)
                        {
                            case Options.OnePlayer:
                                // Partita a un giocatore
                                if (onePlayerGame != null) onePlayerGame();
                                this.Dispose();
                                break;

                            case Options.TwoPlayers:
                                // Partita a due giocatori
                                // if (twoPlayerGame != null) twoPlayerGame();
                                // this.Dispose;
                                break;
                        }
                    }
                }
                else if (InRectangle(startButtonRectangle, oldRightHandPosition))
                {
                    countDown = 100;
                    circularProgressBar.SetProgress(0);
                }

                if (InRectangle(exitButtonRectangle, currentRightHandPosition))
                {
                    --countDown;
                    circularProgressBar.SetProgress(100 - countDown);
                    circularProgressBar.SetPosition(new Vector2(currentRightHandPosition.X, currentRightHandPosition.Y));

                    if (countDown < 0)
                    {
                        Game.Exit();
                    }
                }
                else if (InRectangle(exitButtonRectangle, oldRightHandPosition))
                {
                    countDown = 100;
                    circularProgressBar.SetProgress(0);
                }
            }

            // Rilevamento dello scrolling all'interno della scrollArea
            if (rightScrolling)
            {
                if (InRectangle(scrollArea, currentRightHandPosition) && !(currentRightHandPosition.X > oldRightHandPosition.X))
                {
                    scrollCounter += (int)(oldRightHandPosition.X - currentRightHandPosition.X);

                    if (scrollCounter > 100)
                    {
                        rightTransaction = true;
                        rightScrolling = false;
                        scrollCounter = 0;
                    }
                }
                else
                {
                    rightScrolling = false;
                    scrollCounter = 0;
                }
            }
            else if (leftScrolling)
            {
                if (InRectangle(scrollArea, currentRightHandPosition) && !(currentRightHandPosition.X < oldRightHandPosition.X))
                {
                    scrollCounter += (int)(currentRightHandPosition.X - oldRightHandPosition.X);

                    if (scrollCounter > 100)
                    {
                        leftTransaction = true;
                        leftScrolling = false;
                        scrollCounter = 0;
                    }
                }
                else
                {
                    leftScrolling = false;
                    scrollCounter = 0;
                }
            }

            // Transazione da una pagina all'altra
            if (rightTransaction)
            {
                if (optionTextPosition.X < -menuFont.MeasureString(gameMode[(int)currentOption].Name).X)
                {
                    currentOption = (Options)(((int)(currentOption) + 1) % (int)(Options.NUMBER_OF_OPTIONS));
                    optionTextPosition.X = GraphicsDevice.Viewport.Width;
                }
                else
                {
                    optionTextPosition.X += -40.0f;
                    if (optionTextPosition.X > (GraphicsDevice.Viewport.Width / 2) - 39.0f && optionTextPosition.X < (GraphicsDevice.Viewport.Width / 2) + 39.0f)
                    {
                        optionTextPosition.X = GraphicsDevice.Viewport.Width / 2;
                        rightTransaction = false;
                    }
                }
            }
            else if (leftTransaction)
            {
                if (!(optionTextPosition.X < GraphicsDevice.Viewport.Width))
                {
                    currentOption = (Options)(((int)(currentOption) + 1) % (int)(Options.NUMBER_OF_OPTIONS));
                    optionTextPosition.X = -menuFont.MeasureString(gameMode[(int)currentOption].Name).X;
                }
                else
                {
                    optionTextPosition.X += 40.0f;
                    if ((!(optionTextPosition.X < ((GraphicsDevice.Viewport.Width / 2) - 39.0f))) && (!(optionTextPosition.X > ((GraphicsDevice.Viewport.Width / 2) + 39.0f))))
                    {
                        optionTextPosition.X = GraphicsDevice.Viewport.Width / 2;
                        leftTransaction = false;
                    }
                }
            }
        }

        #endregion


        #region Draw

        public override void Draw(GameTime gameTime)
        {
            spriteBatch.Begin();

            // Sfondo
            spriteBatch.Draw(backgroundTexture, Vector2.Zero, Color.White);
            // Titolo
            spriteBatch.Draw(titleTexture, new Vector2(0, titleY), Color.White);

            // Green stripe
            if (InRectangle(scrollArea, currentRightHandPosition))
            {
                spriteBatch.Draw(greenStripeTexture, scrollArea, Color.DodgerBlue);
            }
            else
            {
                spriteBatch.Draw(greenStripeTexture, scrollArea, Color.Blue);
            }

            // Right handle (with arrows)
            spriteBatch.Draw(rightArrowTexture, rightHandle, Color.White);
            // Left handle (with arrows)
            spriteBatch.Draw(leftArrowTexture, leftHandle, Color.White);

            Vector2 fontSize = menuFont.MeasureString(gameMode[(int)currentOption].Name);
            spriteBatch.DrawString(menuFont, gameMode[(int)currentOption].Name, optionTextPosition - fontSize / 2, Color.Black);

            // Buttons
            if ((InRectangle(startButtonRectangle, currentRightHandPosition)) && (currentOption != Options.TwoPlayers))
            {
                spriteBatch.Draw(startButtonSelectedTexture, startButtonRectangle, Color.White);
                circularProgressBar.Draw(spriteBatch);
            }
            else 
            {
                spriteBatch.Draw(startButtonTexture, startButtonRectangle, Color.White);
            }

            if (InRectangle(exitButtonRectangle, currentRightHandPosition))
            {
                spriteBatch.Draw(exitButtonSelectedTexture, exitButtonRectangle, Color.White);
                circularProgressBar.Draw(spriteBatch);
            }
            else 
            {
                spriteBatch.Draw(exitButtonTexture, exitButtonRectangle, Color.White);
            }

            spriteBatch.Draw(handTexture, new Rectangle((int)currentRightHandPosition.X - 75, (int)currentRightHandPosition.Y - 75, 150, 150), Color.White);

            spriteBatch.End();

            base.Draw(gameTime);
        }

        #endregion


        #region Utilities

        private bool InRectangle(Rectangle rectangle, Vector cursorPosition)
        {
            if ((cursorPosition.X < rectangle.Left || cursorPosition.X > rectangle.Right) ||
                (cursorPosition.Y < rectangle.Top || cursorPosition.Y > rectangle.Bottom))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        #endregion
    }
}
